home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / ingres04.lzh / doc / other / tutorial.doc < prev   
Encoding:
Text File  |  1992-09-11  |  51.6 KB  |  1,675 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.                            A TUTORIAL ON INGRES
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18.  
  19.  
  20.  
  21.  
  22.                                     by
  23.                               Robert Epstein
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31.  
  32.  
  33.  
  34.  
  35.  
  36.  
  37.                         Memorandum No. ERL - M77-25
  38.                              December 15, 1977
  39.                                  (Revised)
  40.  
  41.  
  42.  
  43.                       Electronics Research Laboratory
  44.                           College of Engineering
  45.                     University of California, Berkeley
  46.                                    94720
  47.  
  48.  
  49.  
  50.  
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  
  58.  
  59.  
  60.  
  61.  
  62.                            A Tutorial on INGRES
  63.  
  64.      This tutorial describes how to use the INGRES data  base  manage-
  65.      ment system.  You should be able to follow the the examples given
  66.      here and observe the same results.
  67.  
  68.      The data manipulation language supported by the INGRES system  is
  69.      called  QUEL  (QUEry Language).  Complete information on QUEL and
  70.      INGRES appears in the INGRES  reference  manual.   This  tutorial
  71.      does not attempt to cover every detail of INGRES.
  72.  
  73.      Begin by logging onto UNIX, the time sharing system  under  which
  74.      INGRES  runs.   If  at all possible, use a terminal that has both
  75.      upper and lower case letters;  otherwise  life  is  going  to  be
  76.      miserable  for  you.   If you are on an upper case only terminal,
  77.      type "\\" everywhere "\" appears in the tutorial.
  78.  
  79.      There should currently be a "%" printed  on  your  terminal.   To
  80.      start using INGRES type the command:
  81.  
  82.      % ingres demo
  83.  
  84.      This requests "UNIX" to invoke INGRES using the data base  called
  85.      "demo".  After a few seconds, the following will appear:
  86.  
  87.      INGRES version 6.1/0 login
  88.      Tue Aug 30 14:52:23 1977
  89.  
  90.      COPYRIGHT
  91.      The Regents of the University of California
  92.      1977
  93.  
  94.      This program material is the property of the
  95.      Regents of the University of California and
  96.      may not be reproduced or disclosed without
  97.      the prior written permission of the owner.
  98.  
  99.      go
  100.      *
  101.  
  102.      The first two lines include the INGRES version  number  (in  this
  103.      case  version  6.1)  and the current date.  Following that is the
  104.      "dayfile", which includes messages related to the INGRES  system.
  105.      The "go" indicates that INGRES is ready for your interactions.
  106.  
  107.      The INGRES monitor prints an asterisk ("*") at the  beginning  of
  108.      each line to remind you that INGRES is waiting for input.
  109.  
  110.      Type the command:
  111.  
  112.      * print parts
  113.      * \g
  114.      Executing . . .
  115.  
  116.      The line "print parts" requests a printout of some data stored in
  117.      the  data base.  The "\g" means "go".  The message "Executing . .
  118.      ." indicates that INGRES is processing your query.  The following
  119.      then appears:
  120.  
  121.      parts relation
  122.  
  123.      |pnum  |pname               |color   |weight|qoh   |
  124.      |--------------------------------------------------|
  125.      |     1|central processor   |pink    |    10|     1|
  126.      |     2|memory              |gray    |    20|    32|
  127.      |     3|disk drive          |black   |   685|     2|
  128.      |     4|tape drive          |black   |   450|     4|
  129.      |     5|tapes               |gray    |     1|   250|
  130.      |     6|line printer        |yellow  |   578|     3|
  131.      |     7|l-p paper           |white   |    15|    95|
  132.      |     8|terminals           |blue    |    19|    15|
  133.      |    13|paper tape reader   |black   |   107|     0|
  134.      |    14|paper tape punch    |black   |   147|     0|
  135.      |     9|terminal paper      |white   |     2|   350|
  136.      |    10|byte-soap           |clear   |     0|   143|
  137.      |    11|card reader         |gray    |   327|     0|
  138.      |    12|card punch          |gray    |   427|     0|
  139.      |--------------------------------------------------|
  140.  
  141.      continue
  142.      *
  143.  
  144.      What is printed on your terminal is the "parts relation".  Intui-
  145.      tively,  a  relation  is  nothing more that a table with rows and
  146.      columns.
  147.  
  148.      In this case the  relation  name  is  "parts".   There  are  five
  149.      columns  (we  call  them domains) named pnum (part number), pname
  150.      (part name), color, weight, qoh (quantity on hand).  Each row  of
  151.      the relation (called a tuple) represents one entry, which in this
  152.      case represents one part in a computer installation.  A  relation
  153.      can have up to 49 domains and a virtually unlimited number of tu-
  154.      ples.
  155.  
  156.      Notice that after the query is executed, INGRES  prints  "contin-
  157.      ue",  while when we first entered INGRES it printed "go".  As you
  158.      enter a query INGRES saves what you type in  a  "workspace".   If
  159.      you  ever  mistype  a query, typing "\r" will "reset" (ie. erase)
  160.      your workspace.  (Later on we will learn ways to edit mistakes so
  161.      we don't have to retype the entire query.)
  162.  
  163.      At any time you can see what is in the workspace by typing  "\p".
  164.      Try typing "\p":
  165.  
  166.      * \p
  167.      print parts
  168.      *
  169.  
  170.      The current contents of the workspace is printed.  Now try typing
  171.      "\r":
  172.  
  173.      * \r
  174.      go
  175.      *
  176.  
  177.      The workspace is now empty.  Whenever INGRES types "continue" the
  178.      workspace  is non-empty; whenever INGRES types "go" the workspace
  179.      is empty.
  180.  
  181.      After a query is executed, INGRES typically types "continue".  If
  182.      you then type a new query, INGRES automatically erases the previ-
  183.      ous query, so you don't have to  type  "\r"  after  every  query.
  184.      This will be further explained as we proceed.
  185.  
  186.      Using the "retrieve" command we can write specific queries  about
  187.      relations.   As  an  example,  let's  have  INGRES print only the
  188.      "pname" domain of the parts relation.  Type the command:
  189.  
  190.      * range of p is parts
  191.      * retrieve (p.pname)
  192.      * \g
  193.      Executing . . .
  194.  
  195.  
  196.      |pname               |
  197.      |--------------------|
  198.      |central processor   |
  199.      |memory              |
  200.      |disk drive          |
  201.      |tape drive          |
  202.      |tapes               |
  203.      |line printer        |
  204.      |l-p paper           |
  205.      |terminals           |
  206.      |paper tape reader   |
  207.      |paper tape punch    |
  208.      |terminal paper      |
  209.      |byte-soap           |
  210.      |card reader         |
  211.      |card punch          |
  212.      |--------------------|
  213.  
  214.      continue
  215.      *
  216.  
  217.      The output is just the pname  domain  from  the  parts  relation.
  218.      What we did required two steps.  First we declared what is called
  219.      a "tuple variable" and assigned it to range over the parts  rela-
  220.      tion.
  221.  
  222.      range of p is parts
  223.  
  224.      What this means in English is that the letter "p" represents  the
  225.      parts  relation.   It  may  be thought of as a marker which moves
  226.      down the "parts" relation to keep our  place.   INGRES  remembers
  227.      the  association  so that once p is declared to range over parts,
  228.      we don't have to repeat the range declaration.   This  is  useful
  229.      when  we are working with more than one relation, as will be seen
  230.      later on.
  231.  
  232.      Next we used the retrieve command.  Its form is
  233.  
  234.      retrieve ( list here what you want retrieved )
  235.  
  236.      "p" by itself refers to the parts relation.  "p.pname" refers  to
  237.      the pname domain of the parts relation, so saying:
  238.  
  239.      retrieve (p.pname)
  240.  
  241.      means retrieve the pname domain of the parts relation.
  242.  
  243.      Try the query to retrieve pname and color:
  244.  
  245.      * retrieve p.pname, p.color
  246.      * \g
  247.      Executing . . .
  248.  
  249.      2500: syntax error on line 1
  250.      last symbol read was: .
  251.  
  252.      continue
  253.      *
  254.  
  255.      Unfortunately we've made an error.  INGRES tells us that it found
  256.      a  syntax  error  on the first line of the query.  "Syntax error"
  257.      means that we have typed something which INGRES cannot recognize.
  258.      The  error  occured  on line 1.  INGRES makes a sometimes helpful
  259.      and sometimes feeble attempt at diagnosing the problem.  Whenever
  260.      possible,  INGRES  tells  us the last thing it read before it got
  261.      confused.
  262.  
  263.      In this case, the error is that the list  of  things  to  be  re-
  264.      trieved (called the target list) must be enclosed in parenthesis.
  265.      The correct query is:
  266.  
  267.      * retrieve (p.pname, p.color)
  268.      * \g
  269.      Executing . . .
  270.  
  271.  
  272.      |pname               |color   |
  273.      |-----------------------------|
  274.      |central processor   |pink    |
  275.      |memory              |gray    |
  276.      |disk drive          |black   |
  277.      |tape drive          |black   |
  278.      |tapes               |gray    |
  279.      |line printer        |yellow  |
  280.      |l-p paper           |white   |
  281.      |terminals           |blue    |
  282.      |paper tape reader   |black   |
  283.      |paper tape punch    |black   |
  284.      |terminal paper      |white   |
  285.      |byte-soap           |clear   |
  286.      |card reader         |gray    |
  287.      |card punch          |gray    |
  288.      |-----------------------------|
  289.  
  290.      continue
  291.      *
  292.  
  293.      You can restrict which tuples are printed by adding a "qualifica-
  294.      tion"  to  the  query.   For example to get the name and color of
  295.      only those parts which are gray, type:
  296.  
  297.      * retrieve (p.pname, p.color)
  298.      * where p.color = "gray"
  299.      * \g
  300.      Executing . . .
  301.  
  302.  
  303.      |pname               |color   |
  304.      |-----------------------------|
  305.      |memory              |gray    |
  306.      |tapes               |gray    |
  307.      |card reader         |gray    |
  308.      |card punch          |gray    |
  309.      |-----------------------------|
  310.  
  311.      continue
  312.      *
  313.  
  314.      Notice that INGRES prints only those parts where p.color is gray.
  315.      Notice also that gray must be in quotes ("gray").  This is neces-
  316.      sary.  The only way INGRES will recognize character strings (e.g.
  317.      words) is to enclose them in quotes.
  318.  
  319.      What if we wanted part names for gray or  pink  parts?   We  only
  320.      need to append to the previous query the phrase:
  321.  
  322.      or p.color = "pink"
  323.  
  324.      Remember, however, that if the  next  line  typed  begins  a  new
  325.      query,  INGRES  will  automatically  reset  the  workspace.   The
  326.      workspace will be _s_a_v_e_d only if the next line begins with a  com-
  327.      mand  such as "\p" or "\g".  (There are others which we will come
  328.      to later.) If such a command is  typed,  the  previous  query  is
  329.      saved and anything further will be appended to that query.
  330.  
  331.      Thus, by typing:
  332.  
  333.      * \p
  334.      retrieve (p.pname, p.color)
  335.      where p.color = "gray"
  336.      *
  337.  
  338.      you can see the previous query.  Now type:
  339.  
  340.      * or p.color = "pink"
  341.      *
  342.  
  343.      INGRES appends that last line to the end of the query.   You  can
  344.      verify this yourself by printing the workspace:
  345.  
  346.      * \p
  347.      retrieve (p.pname, p.color)
  348.      where p.color = "gray"
  349.      or p.color = "pink"
  350.      *
  351.  
  352.      Now run the query:
  353.  
  354.      * \g
  355.      Executing . . .
  356.  
  357.  
  358.      |pname               |color   |
  359.      |-----------------------------|
  360.      |central processor   |pink    |
  361.      |memory              |gray    |
  362.      |tapes               |gray    |
  363.      |card reader         |gray    |
  364.      |card punch          |gray    |
  365.      |-----------------------------|
  366.  
  367.      continue
  368.      *
  369.  
  370.      The rules about when the workspace is reset may be very confusing
  371.      at  first.   In  general,  INGRES  will  do exactly what you want
  372.      without you having to think about it.
  373.  
  374.      We have seen qualifications which used "or" and "=".  In  general
  375.      one can use:
  376.  
  377.              and
  378.              or
  379.              not
  380.              =       (equal)
  381.              !=      (not equal)
  382.              >       (greater than)
  383.              >=      (greater than or equal)
  384.              <       (less than)
  385.              <=      (less than or equal)
  386.  
  387.      Evaluation occurs in the order the qualification was  typed  (ie.
  388.      left  to  right).  Parenthesis can be used to group things in any
  389.      arbitrary order.
  390.  
  391.      INGRES can do computations on the data stored in a relation.  For
  392.      example,  the  parts relation has quantity on hand and weight for
  393.      each item.  We might like to know the total weight for each group
  394.      of parts (i.e. weight multiplied by qoh).
  395.  
  396.      To get the name, part number and total weight for each part  type
  397.      the query:
  398.  
  399.      * retrieve (p.pname, p.pnum, p.qoh * p.weight)
  400.      * \g
  401.      Executing . . .
  402.  
  403.      2500: syntax error on line 1
  404.      last symbol read was: *
  405.  
  406.      continue
  407.      *
  408.  
  409.      Another error.  The problem is that when a computation  is  done,
  410.      INGRES  does  not  know  how to title the domain on the printout.
  411.      For a simple domain, INGRES uses the domain name as a title.  For
  412.      anything else, you must create a new domain title by specifying:
  413.  
  414.              tot = p.qoh * p.weight
  415.  
  416.      More generally the form is:
  417.  
  418.              title = expression
  419.  
  420.      For example:
  421.  
  422.              name = p.pname
  423.              computation = p.weight / 2000 * (p.qoh + 2)
  424.  
  425.      Let's fix the error by retyping the query.  As long as the  first
  426.      line after a query does not begin with a "\p" or "\g" then INGRES
  427.      will automatically reset  the  workspace,  erasing  the  previous
  428.      query for us.
  429.  
  430.      * retrieve (p.pname, p.pnum, tot=p.qoh * p.weight)
  431.      * \g
  432.      Executing . . .
  433.  
  434.  
  435.      |pname               |pnum  |tot   |
  436.      |----------------------------------|
  437.      |central processor   |     1|    10|
  438.      |memory              |     2|   640|
  439.      |disk drive          |     3|  1370|
  440.      |tape drive          |     4|  1800|
  441.      |tapes               |     5|   250|
  442.      |line printer        |     6|  1734|
  443.      |l-p paper           |     7|  1425|
  444.      |terminals           |     8|   285|
  445.      |paper tape reader   |    13|     0|
  446.      |paper tape punch    |    14|     0|
  447.      |terminal paper      |     9|   700|
  448.      |byte-soap           |    10|     0|
  449.      |card reader         |    11|     0|
  450.      |card punch          |    12|     0|
  451.      |----------------------------------|
  452.  
  453.      continue
  454.      *
  455.  
  456.      In addition to multiplication, INGRES supports:
  457.  
  458.              +   addition
  459.              -   subtraction (and unary negation)
  460.              /   division
  461.              *   multiplication
  462.              **  exponentiation (e.g. 3**10)
  463.              abs  absolute value (e.g. abs(p.qoh - 50) )
  464.              mod  modulo division
  465.  
  466.      and many others.  Please refer to the INGRES reference manual for
  467.      a brief but complete description of what is supported.
  468.  
  469.      If all we wanted were part numbers 2 or 10, then we could add the
  470.      qualification:
  471.  
  472.              where p.pnum = 2 or p.pnum = 10
  473.  
  474.      CAUTION: if we just started typing "where p.pnum  ....  "  INGRES
  475.      would  understand  this as the beginning of a new query and would
  476.      reset the workspace.  To avoid this you could type "\p" and force
  477.      INGRES  to  print  the  workspace, or you can type "\a" (append).
  478.      The append command guarantees that whatever else is typed will be
  479.      appended  to  what  is already in the workspace.  This command is
  480.      only needed immediately after a query  is  executed.   Any  other
  481.      time data will be appended automatically.  Try the following:
  482.  
  483.      * \a
  484.      * where p.pnum = 2 or p.pnum = 10
  485.      * \g
  486.      Executing . . .
  487.  
  488.  
  489.      |pname               |pnum  |tot   |
  490.      |----------------------------------|
  491.      |memory              |     2|   640|
  492.      |byte-soap           |    10|     0|
  493.      |----------------------------------|
  494.  
  495.      continue
  496.      *
  497.  
  498.      To include all part numbers greater than 2 and less than or equal
  499.      to 10:
  500.  
  501.      * retrieve (p.pname, p.pnum, tot=p.qoh * p.weight)
  502.      * where p.pnum > 2 and p.pnum <= 10
  503.      * \g
  504.      Executing . . .
  505.  
  506.  
  507.      |pname               |pnum  |tot   |
  508.      |----------------------------------|
  509.      |disk drive          |     3|  1370|
  510.      |tape drive          |     4|  1800|
  511.      |tapes               |     5|   250|
  512.      |line printer        |     6|  1734|
  513.      |l-p paper           |     7|  1425|
  514.      |terminals           |     8|   285|
  515.      |terminal paper      |     9|   700|
  516.      |byte-soap           |    10|     0|
  517.      |----------------------------------|
  518.  
  519.      continue
  520.      *
  521.  
  522.      Now, suppose we want to change the previous query to give results
  523.      for  part  numbers between 5 and 10 instead of 2 and 10.  You are
  524.      probably annoyed at having to retype the entire query in order to
  525.      change one character.  Consequently, INGRES lets you use the UNIX
  526.      text  editor  to  make  corrections  and/or  additions  to   your
  527.      workspace.   At any time you can type "\e" and the INGRES monitor
  528.      will write your workspace to a file and call the UNIX  "ed"  pro-
  529.      gram.  For example:
  530.  
  531.      * \e
  532.      >>ed
  533.      83
  534.  
  535.      The ">>ed" message tells you that you are now using  the  editor.
  536.      The number 83 is the number of characters in your workspace.
  537.  
  538.      We can now edit the query by changing the 2 to a 5.  Included  in
  539.      the  UNIX  documentation  is a tutorial on using the text editor.
  540.      Rather than duplicating that tutorial, we will just use a few  of
  541.      the editor commands to illustrate how to do editing:
  542.  
  543.      1p
  544.      retrieve (p.pname,p.pnum,tot = p.qoh * p.weight)
  545.      2p
  546.      where p.pnum > 2 and p.pnum <= 10
  547.      s/2/5/p
  548.      where p.pnum > 5 and p.pnum <= 10
  549.      w
  550.      83
  551.      q
  552.      <<monitor
  553.      *
  554.  
  555.      Very briefly, this is what happens.  "1p" and "2p" printed  lines
  556.      1  and  2.  "s/2/5/p" substitutes a 5 for a 2 on the current line
  557.      (line 2), and then prints that line.  "w" writes the  query  back
  558.      to the INGRES workspace.
  559.  
  560.      Inside the editor you can use any "ed" command except "e"  (since
  561.      e  changes the file name).  When you quit the editor (q command),
  562.      the INGRES monitor will print "<<monitor" to remind you that  you
  563.      are back in INGRES.  Notice that you MUST precede the "q" command
  564.      with a "w" command  to  pass  the  corrected  workspace  back  to
  565.      INGRES.
  566.  
  567.      To verify that the query is correct and to run it, type:
  568.      * \p\g
  569.      retrieve (p.pname,p.pnum,tot = p.qoh * p.weight)
  570.      where p.pnum > 5 and p.pnum <= 10
  571.      Executing . . .
  572.  
  573.  
  574.      |pname               |pnum  |tot   |
  575.      |----------------------------------|
  576.      |line printer        |     6|  1734|
  577.      |l-p paper           |     7|  1425|
  578.      |terminals           |     8|   285|
  579.      |terminal paper      |     9|   700|
  580.      |byte-soap           |    10|     0|
  581.      |----------------------------------|
  582.  
  583.      continue
  584.      *
  585.  
  586.  
  587.      Having exhausted the interesting queries concerning the parts re-
  588.      lation, lets now look at a new relation called "supply".  Type:
  589.  
  590.      * print supply
  591.      * \g
  592.      Executing . . .
  593.  
  594.  
  595.      supply relation
  596.  
  597.      |snum  |pnum  |jnum  |shipdate|quan  |
  598.      |------------------------------------|
  599.      |   475|     1|  1001|73-12-31|     1|
  600.      |   475|     2|  1002|74-05-31|    32|
  601.      |   475|     3|  1001|73-12-31|     2|
  602.      |   475|     4|  1002|74-05-31|     1|
  603.      |   122|     7|  1003|75-02-01|   144|
  604.      |   122|     7|  1004|75-02-01|    48|
  605.      |   122|     9|  1004|75-02-01|   144|
  606.      |   440|     6|  1001|74-10-10|     2|
  607.      |   241|     4|  1001|73-12-31|     1|
  608.      |    62|     3|  1002|74-06-18|     3|
  609.      |   475|     2|  1001|73-12-31|    32|
  610.      |   475|     1|  1002|74-07-01|     1|
  611.      |     5|     4|  1003|74-11-15|     3|
  612.      |     5|     4|  1004|75-01-22|     6|
  613.      |    20|     5|  1001|75-01-10|    20|
  614.      |    20|     5|  1002|75-01-10|    75|
  615.      |   241|     1|  1005|75-06-01|     1|
  616.      |   241|     2|  1005|75-06-01|    32|
  617.      |   241|     3|  1005|75-06-01|     1|
  618.      |    67|     4|  1005|75-07-01|     1|
  619.      |   999|    10|  1006|76-01-01|   144|
  620.      |   241|     8|  1005|75-07-01|     1|
  621.      |   241|     9|  1005|75-07-01|   144|
  622.      |------------------------------------|
  623.  
  624.      continue
  625.      *
  626.  
  627.      The supply relation contains snum  (the  supplier  number),  pnum
  628.      (the  part  number which is supplied by that supplier), jnum (the
  629.      job number), shipdate (the date it was shipped),  and  quan  (the
  630.      quantity shipped).
  631.  
  632.      To find out what parts are supplied by supplier number 122 type:
  633.  
  634.      * retrieve (s.pnum) where s.snum = 122
  635.      * \g
  636.      Executing . . .
  637.  
  638.      2109: line 1, Variable 's' not declared in RANGE statement
  639.  
  640.      continue
  641.      *
  642.  
  643.      We have referenced the tuple variable "s" (i.e.  s.pnum)  without
  644.      telling  INGRES  what "s" represents.  We are missing a range de-
  645.      claration.  Retype the query as follows:
  646.  
  647.      * range of s is supply
  648.      * retrieve (s.pnum) where s.snum = 122
  649.      * \g
  650.      Executing . . .
  651.  
  652.  
  653.      |pnum  |
  654.      |------|
  655.      |     7|
  656.      |     7|
  657.      |     9|
  658.      |------|
  659.  
  660.      continue
  661.      *
  662.  
  663.      Supplier number 122 supplies part numbers 7, 7 and 9.  Note  that
  664.      7  is listed twice.  When retrieving tuples onto a terminal it is
  665.      more efficient for INGRES NOT  to  check  for  duplicate  tuples.
  666.      INGRES can be forced to remove duplicate tuples.  We will come to
  667.      that later.
  668.  
  669.      We now know that supplier 122 supplies part numbers 7 and 9.   If
  670.      you haven't run this query a few hundred times you probably don't
  671.      know what part names correspond to part  numbers  7  and  9.   We
  672.      could find out simply by running the query:
  673.  
  674.      * retrieve (p.pname) where p.pnum = 7 or
  675.      * p.pnum = 9
  676.      * \g
  677.      Executing . . .
  678.  
  679.  
  680.      |pname               |
  681.      |--------------------|
  682.      |l-p paper           |
  683.      |terminal paper      |
  684.      |--------------------|
  685.  
  686.      continue
  687.      *
  688.  
  689.      After two queries we know by part name what parts are supplied by
  690.      supplier  number 122.  We could do the same thing in one query by
  691.      asking:
  692.  
  693.      * retrieve (p.pname) where p.pnum = s.pnum
  694.      * and s.snum = 122
  695.      * \g
  696.      Executing . . .
  697.  
  698.  
  699.      |pname               |
  700.      |--------------------|
  701.      |l-p paper           |
  702.      |l-p paper           |
  703.      |terminal paper      |
  704.      |--------------------|
  705.  
  706.      continue
  707.      *
  708.  
  709.      Again note that "l-p paper" is duplicated.  Look closely at  this
  710.      query.   Note  that  the domain pnum exists in both the parts and
  711.      supply relations.  By saying p.pnum = s.pnum,  we  are  logically
  712.      joining the two relations.
  713.  
  714.      Suppose we wished to find all suppliers who  supply  the  central
  715.      processor.   We  know  that  we will want to retrieve s.snum.  We
  716.      want only those s.snum's where the corresponding s.pnum is  equal
  717.      to the part number for the central processor.
  718.  
  719.      If we find the p.pname which is equal to "central processor" then
  720.      that  will  tell us the correct p.pnum.  Finally we want s.pnum =
  721.      p.pnum.  The query is:
  722.  
  723.      * retrieve (s.snum) where
  724.      * s.pnum = p.pnum and p.pname = "central processor"
  725.      * \g
  726.      Executing . . .
  727.  
  728.  
  729.      |snum  |
  730.      |------|
  731.      |   475|
  732.      |   475|
  733.      |   241|
  734.      |------|
  735.  
  736.      continue
  737.      *
  738.  
  739.      Let's abandon the parts and supply  relations  and  try  another.
  740.      First,  we  can  see  what other relations are in the database by
  741.      typing:
  742.  
  743.      * help \g
  744.      * Executing . . .
  745.  
  746.  
  747.       relation name     relation owner
  748.  
  749.       relation          ingres
  750.       attribute         ingres
  751.       indexes           ingres
  752.       integrity         ingres
  753.       constraint        ingres
  754.       item              ingres
  755.       sale              ingres
  756.       employee          ingres
  757.       dept              ingres
  758.       supplier          ingres
  759.       store             ingres
  760.       parts             ingres
  761.       supply            ingres
  762.  
  763.  
  764.      continue
  765.      *
  766.  
  767.      Let's look at the "employee" relation.   Since  we  know  nothing
  768.      about  the  relation  we can also use the "help" command to learn
  769.      about it.  Type:
  770.  
  771.      * help employee
  772.      * \g
  773.      Executing . . .
  774.  
  775.  
  776.      Relation:               employee
  777.      Owner:                  ingres
  778.      Tuple width:            30
  779.      Saved until:            Fri Mar 25 11:01:30 1977
  780.      Number of tuples:       24
  781.      Storage structure:      paged heap
  782.      relation type:          user relation
  783.  
  784.       attribute name    type  length  keyno.
  785.  
  786.       number             i       2
  787.       name               c      20
  788.       salary             i       2
  789.       manager            i       2
  790.       birthdate          i       2
  791.       startdate          i       2
  792.  
  793.  
  794.      continue
  795.      *
  796.  
  797.      The help command lists overall information about the employee re-
  798.      lation together with each attribute, its type and its length.
  799.  
  800.      INGRES supports three data types: integer numbers, floating point
  801.      numbers, and characters strings.  Character domains can be from 1
  802.      to 255 characters in length.  Integer domains can be 1, 2,  or  4
  803.      bytes  in  length.  This means that integers can obtain a maximum
  804.      value of 127; 32,767; and 2,147,483,647  respectively.   Floating
  805.      point  numbers  can  be either 4 or 8 bytes.  Both hold a maximum
  806.      value of about 10**38; with 7 or 17 digit accuracy respectively.
  807.  
  808.      To look at all domains we could use the print command or we could
  809.      use the retrieve command and list each domain in the target list.
  810.      INGRES provides a shorthand way of doing just that.  Try the fol-
  811.      lowing:
  812.  
  813.      * range of e is employee
  814.      * retrieve (e.all)
  815.      * \g
  816.      Executing . . .
  817.  
  818.  
  819.      |number|name                |salary|manage|birthd|startd|
  820.      |-------------------------------------------------------|
  821.      |   157|Jones, Tim          | 12000|   199|  1940|  1960|
  822.      |  1110|Smith, Paul         |  6000|    33|  1952|  1973|
  823.      |    35|Evans, Michael      |  5000|    32|  1952|  1974|
  824.      |   129|Thomas, Tom         | 10000|   199|  1941|  1962|
  825.      |    13|Edwards, Peter      |  9000|   199|  1928|  1958|
  826.      |   215|Collins, Joanne     |  7000|    10|  1950|  1971|
  827.      |    55|James, Mary         | 12000|   199|  1920|  1969|
  828.      |    26|Thompson, Bob       | 13000|   199|  1930|  1970|
  829.      |    98|Williams, Judy      |  9000|   199|  1935|  1969|
  830.      |    32|Smythe, Carol       |  9050|   199|  1929|  1967|
  831.      |    33|Hayes, Evelyn       | 10100|   199|  1931|  1963|
  832.      |   199|Bullock, J.D.       | 27000|     0|  1920|  1920|
  833.      |  4901|Bailey, Chas M.     |  8377|    32|  1956|  1975|
  834.      |   843|Schmidt, Herman     | 11204|    26|  1936|  1956|
  835.      |  2398|Wallace, Maggie J.  |  7880|    26|  1940|  1959|
  836.      |  1639|Choy, Wanda         | 11160|    55|  1947|  1970|
  837.      |  5119|Ferro, Tony         | 13621|    55|  1939|  1963|
  838.      |    37|Raveen, Lemont      | 11985|    26|  1950|  1974|
  839.      |  5219|Williams, Bruce     | 13374|    33|  1944|  1959|
  840.      |  1523|Zugnoni, Arthur A.  | 19868|   129|  1928|  1949|
  841.      |   430|Brunet, Paul C.     | 17674|   129|  1938|  1959|
  842.      |   994|Iwano, Masahiro     | 15641|   129|  1944|  1970|
  843.      |  1330|Onstad, Richard     |  8779|    13|  1952|  1971|
  844.      |    10|Ross, Stanley       | 15908|   199|  1927|  1945|
  845.      |    11|Ross, Stuart        | 12067|     0|  1931|  1932|
  846.      |-------------------------------------------------------|
  847.  
  848.      continue
  849.      *
  850.  
  851.      "All" is a keyword which is expanded  by  INGRES  to  become  all
  852.      domains.   The domains are not guaranteed to be in any particular
  853.      order.  The previous query is equivalent to:
  854.  
  855.              range of e is employee
  856.              retrieve (e.number, e.name, e.salary, e.manager
  857.                      e.birthdate, e.startdate)
  858.  
  859.      Let's retrieve the salary of Stan Ross.  At this  point  we  will
  860.      need  to  be  able to type both upper and lower case letters.  If
  861.      you are on an upper case only terminal, type a single "\"  before
  862.      a letter you wish to capitalize.  Thus on an upper case only ter-
  863.      minal type "\ROSS, \STAN".  If you are on an upper and lower case
  864.      terminal, use the shift key to capitalize a letter.
  865.  
  866.      Run the query:
  867.  
  868.      * retrieve (e.name,e.salary)
  869.      * where e.name = "Ross, Stan"
  870.      * \g
  871.      Executing . . .
  872.  
  873.  
  874.      |name                |salary|
  875.      |---------------------------|
  876.      |---------------------------|
  877.  
  878.      continue
  879.      *
  880.  
  881.      The result is empty.  There is  no  e.name  which  satisfies  the
  882.      qualification.   That's  strange  because we know there is a Stan
  883.      Ross.  However, INGRES does not know, for example, that "Stanley"
  884.      and "Stan" are semantically the same.
  885.  
  886.      To get the correct answer in this situation you may use the  spe-
  887.      cial "pattern matching" characters provided by INGRES.
  888.  
  889.      One such character is "*".  It matches any string of zero or more
  890.      characters.  Try the query:
  891.  
  892.      * retrieve (e.name,e.salary)
  893.      * where e.name = "Ross, S*"
  894.      * \g
  895.      Executing . . .
  896.  
  897.  
  898.      |name                |salary|
  899.      |---------------------------|
  900.      |Ross, Stanley       | 15908|
  901.      |Ross, Stuart        | 12067|
  902.      |---------------------------|
  903.  
  904.      continue
  905.      *
  906.  
  907.      In the first case "*" matched the  string  "tanley"  and  in  the
  908.      second case it matched "tuart".
  909.  
  910.      Here is another example.  Find the salaries of all  people  whose
  911.      first name is "Paul":
  912.  
  913.      * retrieve (e.name,e.salary)
  914.      * where e.name = "*,Paul*"
  915.      * \g
  916.      Executing . . .
  917.  
  918.  
  919.      |name                |salary|
  920.      |---------------------------|
  921.      |Smith, Paul         |  6000|
  922.      |Brunet, Paul C.     | 17674|
  923.      |---------------------------|
  924.  
  925.      continue
  926.      *
  927.  
  928.      Notice that if we had asked for e.name = "*,Paul"  we  would  not
  929.      have gotten the second tuple.  Also, INGRES ignores blanks in any
  930.      character comparison whether using pattern matching characters or
  931.      not.   This  means  that  the  following  would all give the same
  932.      results:
  933.  
  934.              e.name = "Ross,Stanley"
  935.              e.name = "Ross,   Stanley   "
  936.              e.name = "R o s s,Stanley"
  937.  
  938.      Particular characters or ranges  of  characters  can  be  put  in
  939.      square  brackets  ([]).  For example, find all people whose names
  940.      start with "B" through "F":
  941.  
  942.      * retrieve (e.name,e.salary)
  943.      * where e.name = "[B-F]*"
  944.  
  945.      * \g
  946.      Executing . . .
  947.  
  948.  
  949.      |name                |salary|
  950.      |---------------------------|
  951.      |Evans, Michael      |  5000|
  952.      |Edwards, Peter      |  9000|
  953.      |Collins, Joanne     |  7000|
  954.      |Bullock, J.D.       | 27000|
  955.      |Bailey, Chas M.     |  8377|
  956.      |Choy, Wanda         | 11160|
  957.      |Ferro, Tony         | 13621|
  958.      |Brunet, Paul C.     | 17674|
  959.      |---------------------------|
  960.  
  961.      continue
  962.      *
  963.  
  964.      Notice that this last query could be done another way:
  965.  
  966.      * retrieve (e.name,e.salary)
  967.      * where e.name >"B" and e.name <"G"
  968.      * \g
  969.      Executing . . .
  970.  
  971.  
  972.      |name                |salary|
  973.      |---------------------------|
  974.      |Evans, Michael      |  5000|
  975.      |Edwards, Peter      |  9000|
  976.      |Collins, Joanne     |  7000|
  977.      |Bullock, J.D.       | 27000|
  978.      |Bailey, Chas M.     |  8377|
  979.      |Choy, Wanda         | 11160|
  980.      |Ferro, Tony         | 13621|
  981.      |Brunet, Paul C.     | 17674|
  982.      |---------------------------|
  983.  
  984.      continue
  985.      *
  986.  
  987.      The two results are identical; however, the second  way  is  gen-
  988.      erally more efficient for INGRES to process.
  989.  
  990.      There are three types of pattern matching constructs.  All  three
  991.      can  be  used  in any combination for character comparison.  They
  992.      are:
  993.  
  994.          *   matches any length character string
  995.          ?   matches any one (non-blank) character
  996.          [ ] can match any character listed in the brackets.   If  two
  997.              characters  are  separated by a dash (-), then it matches
  998.              any character falling between the two characters.
  999.  
  1000.      The special meaning of a pattern matching character can be turned
  1001.      off  by preceeding it with a "\".  This means that "\*" refers to
  1002.      the character "*".
  1003.  
  1004.      We turn now to the aggregation facilities  supported  by  INGRES.
  1005.      This  allows a user to perform computations on whole domains of a
  1006.      relation.  For example, one aggregate is average (avg).  To  com-
  1007.      pute the average salary for all employees, we enter:
  1008.  
  1009.      * retrieve (avgsal=avg(e.salary))
  1010.      * \g
  1011.      Executing . . .
  1012.  
  1013.  
  1014.      |avgsal    |
  1015.      |----------|
  1016.      | 11867.520|
  1017.      |----------|
  1018.  
  1019.      continue
  1020.      *
  1021.  
  1022.      The particular title "avgsal" is arbitrary, but necessary; INGRES
  1023.      needs  _s_o_m_e  sort  of title for any expression in the target list
  1024.      (other than a simple domain).
  1025.  
  1026.      We can also find the minimum and maximum salaries:
  1027.  
  1028.      * retrieve (minsal=min(e.salary),maxsal=max(e.salary))
  1029.      * \g
  1030.      Executing . . .
  1031.  
  1032.  
  1033.      |minsal|maxsal|
  1034.      |-------------|
  1035.      |  5000| 27000|
  1036.      |-------------|
  1037.  
  1038.      continue
  1039.      *
  1040.  
  1041.      If we wanted to know the names of  the  employees  who  make  the
  1042.      minimum and maximum salaries, that query would be:
  1043.  
  1044.      * retrieve (e.name, e.salary)
  1045.      * where e.salary = min(e.salary) or e.salary = max(e.salary)
  1046.      * \g
  1047.      Executing . . .
  1048.  
  1049.      |name                |salary|
  1050.      |---------------------------|
  1051.      |Evans, Michael      |  5000|
  1052.      |Bullock, J.D.       | 27000|
  1053.      |---------------------------|
  1054.  
  1055.      continue
  1056.      *
  1057.  
  1058.      INGRES supports the following aggregates:
  1059.  
  1060.              count
  1061.              min
  1062.              max
  1063.              avg
  1064.              sum
  1065.              any
  1066.  
  1067.      We now indicate the query to list each employee  along  with  the
  1068.      average salary for all employees:
  1069.  
  1070.      * retrieve (e.name,peersal=avg(e.salary))
  1071.      * \g
  1072.      Executing . . .
  1073.  
  1074.  
  1075.      |name                |peersal   |
  1076.      |-------------------------------|
  1077.      |Jones, Tim          | 11867.520|
  1078.      |Smith, Paul         | 11867.520|
  1079.      |Evans, Michael      | 11867.520|
  1080.      |Thomas, Tom         | 11867.520|
  1081.      |Edwards, Peter      | 11867.520|
  1082.      |Collins, Joanne     | 11867.520|
  1083.      |James, Mary         | 11867.520|
  1084.      |Thompson, Bob       | 11867.520|
  1085.      |Williams, Judy      | 11867.520|
  1086.      |Smythe, Carol       | 11867.520|
  1087.      |Hayes, Evelyn       | 11867.520|
  1088.      |Bullock, J.D.       | 11867.520|
  1089.      |Bailey, Chas M.     | 11867.520|
  1090.      |Schmidt, Herman     | 11867.520|
  1091.      |Wallace, Maggie J.  | 11867.520|
  1092.      |Choy, Wanda         | 11867.520|
  1093.      |Ferro, Tony         | 11867.520|
  1094.      |Raveen, Lemont      | 11867.520|
  1095.      |Williams, Bruce     | 11867.520|
  1096.      |Zugnoni, Arthur A.  | 11867.520|
  1097.      |Brunet, Paul C.     | 11867.520|
  1098.      |Iwano, Masahiro     | 11867.520|
  1099.      |Onstad, Richard     | 11867.520|
  1100.      |Ross, Stanley       | 11867.520|
  1101.      |Ross, Stuart        | 11867.520|
  1102.      |-------------------------------|
  1103.  
  1104.      continue
  1105.      *
  1106.  
  1107.      An aggregate always evaluates to a single value.  To process  the
  1108.      last  query,  INGRES  replicated  the average salary next to each
  1109.      e.name.
  1110.  
  1111.      Aggregates can have their own qualification.  For example, we can
  1112.      retrieve a list of each employee along with the average salary of
  1113.      those employees over 50.
  1114.  
  1115.      * retrieve (e.name,peersal=
  1116.      * avg(e.salary where 1977-e.birthdate > 50))
  1117.      * \g
  1118.      Executing . . .
  1119.  
  1120.  
  1121.      |name                |peersal   |
  1122.      |-------------------------------|
  1123.      |Jones, Tim          | 19500.000|
  1124.      |Smith, Paul         | 19500.000|
  1125.      |Evans, Michael      | 19500.000|
  1126.      |Thomas, Tom         | 19500.000|
  1127.      |Edwards, Peter      | 19500.000|
  1128.      |Collins, Joanne     | 19500.000|
  1129.      |James, Mary         | 19500.000|
  1130.      |Thompson, Bob       | 19500.000|
  1131.      |Williams, Judy      | 19500.000|
  1132.      |Smythe, Carol       | 19500.000|
  1133.      |Hayes, Evelyn       | 19500.000|
  1134.      |Bullock, J.D.       | 19500.000|
  1135.      |Bailey, Chas M.     | 19500.000|
  1136.      |Schmidt, Herman     | 19500.000|
  1137.      |Wallace, Maggie J.  | 19500.000|
  1138.      |Choy, Wanda         | 19500.000|
  1139.      |Ferro, Tony         | 19500.000|
  1140.      |Raveen, Lemont      | 19500.000|
  1141.      |Williams, Bruce     | 19500.000|
  1142.      |Zugnoni, Arthur A.  | 19500.000|
  1143.      |Brunet, Paul C.     | 19500.000|
  1144.      |Iwano, Masahiro     | 19500.000|
  1145.      |Onstad, Richard     | 19500.000|
  1146.      |Ross, Stanley       | 19500.000|
  1147.      |Ross, Stuart        | 19500.000|
  1148.      |-------------------------------|
  1149.  
  1150.      continue
  1151.      *
  1152.  
  1153.      Contrast the previous query with this next one.  We will retrieve
  1154.      the  names of those employees over fifty and retrieve the average
  1155.      salary for all employees.
  1156.  
  1157.      * retrieve (e.name,peersal=avg(e.salary))
  1158.      * where 1977-e.birthdate > 50
  1159.      * \g
  1160.      Executing . . .
  1161.  
  1162.  
  1163.      |name                |peersal   |
  1164.      |-------------------------------|
  1165.      |James, Mary         | 11867.520|
  1166.      |Bullock, J.D.       | 11867.520|
  1167.      |-------------------------------|
  1168.  
  1169.      continue
  1170.      *
  1171.  
  1172.      There is a very important  distinction  between  these  last  two
  1173.      queries.   An  aggregate is completely self-contained.  It is not
  1174.      affected by the qualification of the query as a whole.
  1175.  
  1176.      In the first case, average is computed only for  those  employees
  1177.      over fifty, and all employees are retrieved.  In the second case,
  1178.      however, average is computed for all employees but only those em-
  1179.      ployees over 50 are retrieved.
  1180.  
  1181.      If we wanted a list of all employees over fifty together with the
  1182.      average salary of employees over fifty, we would combine the pre-
  1183.      vious two queries into one.  That query would be:
  1184.  
  1185.      * retrieve (e.name, peersal=
  1186.      * avg(e.salary where 1977 - e.birthdate > 50))
  1187.      * where 1977 - e.birthdate > 50
  1188.      * \g
  1189.      Executing . . .
  1190.  
  1191.  
  1192.      |name                |peersal   |
  1193.      |-------------------------------|
  1194.      |James, Mary         | 19500.000|
  1195.      |Bullock, J.D.       | 19500.000|
  1196.      |-------------------------------|
  1197.  
  1198.      continue
  1199.      *
  1200.  
  1201.      It is sometimes useful to have duplicate values removed before an
  1202.      aggregation  is  computed.  For example if you wanted to know how
  1203.      many managers there are, the following query will  not  give  the
  1204.      right answer:
  1205.  
  1206.      * retrieve (bosses = count(e.manager))
  1207.      * \g
  1208.      * Executing . . .
  1209.  
  1210.  
  1211.      |bosses       |
  1212.      |-------------|
  1213.      |           25|
  1214.      |-------------|
  1215.  
  1216.      continue
  1217.      *
  1218.  
  1219.      Notice that that gives the count of how many tuples there are  in
  1220.      employee.   What  we  want to know is how many unique e.manager's
  1221.      there are.
  1222.  
  1223.      INGRES provides three special forms of aggregation.
  1224.  
  1225.              countu          count unique values
  1226.              avgu            average unique values
  1227.              sumu            sum unique values
  1228.  
  1229.      It's interesting to note that minu, maxu, and anyu are not  need-
  1230.      ed.   Their  values would be the same whether duplicates were re-
  1231.      moved or not.
  1232.  
  1233.      The correct query to find the number of managers is:
  1234.  
  1235.      * retrieve (bosses=countu(e.manager))
  1236.      * \g
  1237.      Executing . . .
  1238.  
  1239.  
  1240.      |bosses       |
  1241.      |-------------|
  1242.      |            9|
  1243.      |-------------|
  1244.  
  1245.      continue
  1246.      *
  1247.  
  1248.      Another aggregate facility supported by INGRES is  called  aggre-
  1249.      gate  functions.   Aggregate functions group data into categories
  1250.      and perform separate aggregations on each category.
  1251.  
  1252.      For example, what if you wanted to retrieve  each  employee,  and
  1253.      the average salary paid to employees with the same manager?  That
  1254.      query would be:
  1255.  
  1256.      * retrieve (e.name,manageravg=avg(e.salary by e.manager))
  1257.      * \g
  1258.  
  1259.      Executing . . .
  1260.  
  1261.  
  1262.      |name                |manageravg|
  1263.      |-------------------------------|
  1264.      |Jones, Tim          | 11117.555|
  1265.      |Thomas, Tom         | 11117.555|
  1266.      |Edwards, Peter      | 11117.555|
  1267.      |James, Mary         | 11117.555|
  1268.      |Thompson, Bob       | 11117.555|
  1269.      |Williams, Judy      | 11117.555|
  1270.      |Smythe, Carol       | 11117.555|
  1271.      |Hayes, Evelyn       | 11117.555|
  1272.      |Ross, Stanley       | 11117.555|
  1273.      |Smith, Paul         |  9687.000|
  1274.      |Williams, Bruce     |  9687.000|
  1275.      |Evans, Michael      |  6688.500|
  1276.      |Bailey, Chas M.     |  6688.500|
  1277.      |Collins, Joanne     |  7000.000|
  1278.      |Bullock, J.D.       | 19533.500|
  1279.      |Ross, Stuart        | 19533.500|
  1280.      |Schmidt, Herman     | 10356.333|
  1281.      |Wallace, Maggie J.  | 10356.333|
  1282.      |Raveen, Lemont      | 10356.333|
  1283.      |Choy, Wanda         | 12390.500|
  1284.      |Ferro, Tony         | 12390.500|
  1285.      |Zugnoni, Arthur A.  | 17727.666|
  1286.      |Brunet, Paul C.     | 17727.666|
  1287.      |Iwano, Masahiro     | 17727.666|
  1288.      |Onstad, Richard     |  8779.000|
  1289.      |-------------------------------|
  1290.  
  1291.      continue
  1292.      *
  1293.  
  1294.      The first nine people all have the same manager and their average
  1295.      salary  is  11117.555.  The next two people have the same manager
  1296.      and their average salary is 9687. etc.
  1297.  
  1298.      Once again, if we wanted to see the same list just for those  em-
  1299.      ployees over 50:
  1300.  
  1301.      * retrieve (e.name,manageravg=avg(e.salary by e.manager))
  1302.      * where 1977-e.birthdate > 50
  1303.      * \g
  1304.      Executing . . .
  1305.  
  1306.  
  1307.      |name                |manageravg|
  1308.      |-------------------------------|
  1309.      |James, Mary         | 11117.555|
  1310.      |Bullock, J.D.       | 19533.500|
  1311.      |-------------------------------|
  1312.  
  1313.      continue
  1314.      *
  1315.  
  1316.      Aggregate functions (unlike simple aggregates) are not completely
  1317.      local  to themselves.  The domains upon which the data is grouped
  1318.      (called the by-list) are logically connected to  the  domains  in
  1319.      the rest of the query.
  1320.  
  1321.      In these last examples, the "e.manager" in the by-list refers  to
  1322.      the same tuple as "e.name" in the target list.
  1323.  
  1324.      If we wanted to compute the average salaries by manager for  only
  1325.      managers 33 and 199, then the query would be:
  1326.  
  1327.      * retrieve (e.name,manageravg=
  1328.      * avg(e.salary by e.manager)
  1329.      * where e.manager = 199 or e.manager = 33
  1330.      * \g
  1331.      Executing . . .
  1332.  
  1333.  
  1334.      |name                |manageravg|
  1335.      |-------------------------------|
  1336.      |Jones, Tim          | 11117.555|
  1337.      |Thomas, Tom         | 11117.555|
  1338.      |Edwards, Peter      | 11117.555|
  1339.      |James, Mary         | 11117.555|
  1340.      |Thompson, Bob       | 11117.555|
  1341.      |Williams, Judy      | 11117.555|
  1342.      |Smythe, Carol       | 11117.555|
  1343.      |Hayes, Evelyn       | 11117.555|
  1344.      |Ross, Stanley       | 11117.555|
  1345.      |Smith, Paul         |  9687.000|
  1346.      |Williams, Bruce     |  9687.000|
  1347.      |-------------------------------|
  1348.  
  1349.      continue
  1350.      *
  1351.  
  1352.      Suppose we wanted to find out  how  many  people  work  for  each
  1353.      manager,  and  in addition wanted only to include those employees
  1354.      who have worked at least seven years.
  1355.  
  1356.      * retrieve (e.manager,people=count(e.name by e.manager where
  1357.      * e.startdate < 1970))
  1358.      * \g
  1359.      Executing . . .
  1360.  
  1361.  
  1362.      |manage|people       |
  1363.      |--------------------|
  1364.      |   199|            8|
  1365.      |    33|            2|
  1366.      |    32|            0|
  1367.      |    10|            0|
  1368.      |     0|            2|
  1369.      |    26|            2|
  1370.      |    55|            1|
  1371.      |   129|            2|
  1372.      |    13|            0|
  1373.      |--------------------|
  1374.  
  1375.      continue
  1376.      *
  1377.  
  1378.      Notice that managers 32, 10, and 13 have no employees who started
  1379.      before  1970.  Now suppose we want to know the average salary for
  1380.      those employees.  Simply change "count" to "avg"  and  rerun  the
  1381.      query.
  1382.  
  1383.      * retrieve (e.manager,people=avg(e.salary by e.manager where
  1384.      * e.startdate < 1970))
  1385.      * \g
  1386.      Executing . . .
  1387.  
  1388.  
  1389.      |manage|people    |
  1390.      |-----------------|
  1391.      |   199| 10882.250|
  1392.      |    33| 22687.000|
  1393.      |    32|     0.000|
  1394.      |    10|     0.000|
  1395.      |     0| 19533.500|
  1396.      |    26|  9542.000|
  1397.      |    55| 13621.000|
  1398.      |   129| 18771.000|
  1399.      |    13|     0.000|
  1400.      |-----------------|
  1401.  
  1402.      continue
  1403.      *
  1404.  
  1405.      Notice what INGRES does for managers 32, 10 and 13.  The  average
  1406.      salary  for  those  manager employees is actually undefined since
  1407.      there are no employees who started before  1970.   INGRES  always
  1408.      makes undefined values zero in aggregates.
  1409.  
  1410.      If you want to remove the zero values from the output, a qualifi-
  1411.      cation  can  be added to the query. The following query will find
  1412.      the average salaries only for those which are greater than zero.
  1413.  
  1414.      * retrieve (e.manager,people=avg(e.salary by e.manager where
  1415.      * e.startdate < 1970))
  1416.      * where avg(e.salary by e.manager where e.startdate < 1970) > 0
  1417.      * \g
  1418.      Executing . . .
  1419.  
  1420.  
  1421.      |manage|people    |
  1422.      |-----------------|
  1423.      |   199| 10882.250|
  1424.      |    33| 22687.000|
  1425.      |     0| 19533.500|
  1426.      |    26|  9542.000|
  1427.      |    55| 13621.000|
  1428.      |   129| 18771.000|
  1429.      |-----------------|
  1430.  
  1431.      continue
  1432.      *
  1433.  
  1434.      Up until now we have been retrieving results  directly  onto  the
  1435.      terminal.   You  can  also save results by retrieving them into a
  1436.      new relation.  This is done by saying:
  1437.  
  1438.              retrieve into newrel ( ... )
  1439.              where . . .
  1440.  
  1441.      The rules are exactly the same as for retrieves onto  the  termi-
  1442.      nal.   INGRES  will  create  the  new  relation  with the correct
  1443.      domains, and then put the results of the query in the  new  rela-
  1444.      tion.
  1445.  
  1446.      For example, create a new relation called  "overpaid"  which  has
  1447.      only those employees who make more than $8000:
  1448.  
  1449.      * retrieve into overpaid (e.all)
  1450.      * where e.salary > 8000
  1451.      * print overpaid
  1452.      * \g
  1453.      Executing . . .
  1454.  
  1455.  
  1456.      overpaid relation
  1457.  
  1458.      |number|name                |salary|manage|birthd|startd|
  1459.      |-------------------------------------------------------|
  1460.      |    10|Ross, Stanley       | 15908|   199|  1927|  1945|
  1461.      |    11|Ross, Stuart        | 12067|     0|  1931|  1932|
  1462.      |    13|Edwards, Peter      |  9000|   199|  1928|  1958|
  1463.      |    26|Thompson, Bob       | 13000|   199|  1930|  1970|
  1464.      |    32|Smythe, Carol       |  9050|   199|  1929|  1967|
  1465.      |    33|Hayes, Evelyn       | 10100|   199|  1931|  1963|
  1466.      |    37|Raveen, Lemont      | 11985|    26|  1950|  1974|
  1467.      |    55|James, Mary         | 12000|   199|  1920|  1969|
  1468.      |    98|Williams, Judy      |  9000|   199|  1935|  1969|
  1469.      |   129|Thomas, Tom         | 10000|   199|  1941|  1962|
  1470.      |   157|Jones, Tim          | 12000|   199|  1940|  1960|
  1471.      |   199|Bullock, J.D.       | 27000|     0|  1920|  1920|
  1472.      |   430|Brunet, Paul C.     | 17674|   129|  1938|  1959|
  1473.      |   843|Schmidt, Herman     | 11204|    26|  1936|  1956|
  1474.      |   994|Iwano, Masahiro     | 15641|   129|  1944|  1970|
  1475.      |  1330|Onstad, Richard     |  8779|    13|  1952|  1971|
  1476.      |  1523|Zugnoni, Arthur A.  | 19868|   129|  1928|  1949|
  1477.      |  1639|Choy, Wanda         | 11160|    55|  1947|  1970|
  1478.      |  4901|Bailey, Chas M.     |  8377|    32|  1956|  1975|
  1479.      |  5119|Ferro, Tony         | 13621|    55|  1939|  1963|
  1480.      |  5219|Williams, Bruce     | 13374|    33|  1944|  1959|
  1481.      |-------------------------------------------------------|
  1482.  
  1483.      continue
  1484.      *
  1485.  
  1486.      On a "retrieve into" nothing is printed.  We  had  to  include  a
  1487.      "print" command to see the results.  Also, the relation name on a
  1488.      "retrieve into" must not already exist.  For example, if we tried
  1489.      the same query again:
  1490.  
  1491.      * \g
  1492.      Executing . . .
  1493.  
  1494.      5102: CREATE: duplicate relation name overpaid
  1495.  
  1496.      continue
  1497.      *
  1498.  
  1499.      There are two special features about a "retrieve  into".   First,
  1500.      the result relation is automatically sorted and any duplicate tu-
  1501.      ples are removed.  Second, the relation becomes part of the  data
  1502.      base  and  is owned by you.  If you don't want it to be saved you
  1503.      should remember to destroy it.  The mechanism  for  destroying  a
  1504.      relation will be mentioned a bit later.
  1505.  
  1506.      So far we have only retrieved data but never changed it.   INGRES
  1507.      supports three update commands: append, replace, and delete.
  1508.  
  1509.      For example, to add "Tom Terrific" to the list  of  overpaid  em-
  1510.      ployees and start him off at $10000:
  1511.  
  1512.      * append to overpaid(name = "Terrific, Tom",salary = 10000)
  1513.      * \g
  1514.      Executing . . .
  1515.  
  1516.  
  1517.      continue
  1518.      *
  1519.  
  1520.      Notice that we specified values for only two of the  six  domains
  1521.      in  "overpaid".   That  is  fine.   INGRES will automatically set
  1522.      numeric domains to zero and character domains to blank,  if  they
  1523.      are not specified.
  1524.  
  1525.      Notice also that INGRES did not print anything after  the  query.
  1526.      This is true for all update commands.
  1527.  
  1528.      Let's give everyone in overpaid a 10% raise.  To do this we  want
  1529.      to replace o.salary by 1.1 times its value.  Type the query:
  1530.  
  1531.      * range of o is overpaid
  1532.      * replace o(salary = o.salary * 1.1)
  1533.      * \g
  1534.      Executing . . .
  1535.  
  1536.  
  1537.      continue
  1538.      *
  1539.  
  1540.      While the append command requires that you give a  relation  name
  1541.      (e.g.  append  to  overpaid), the replace and delete commands re-
  1542.      quire a tuple variable.  Note that the command is:
  1543.  
  1544.              replace o ( . . . )
  1545.                      where . . .
  1546.  
  1547.      and not:
  1548.  
  1549.              replace overpaid ( . . . )
  1550.                      where . . .
  1551.  
  1552.      Print the results of these last two updates:
  1553.  
  1554.      * print overpaid
  1555.      * \g
  1556.      Executing . . .
  1557.  
  1558.  
  1559.      overpaid relation
  1560.  
  1561.      |number|name                |salary|manage|birthd|startd|
  1562.      |-------------------------------------------------------|
  1563.      |    10|Ross, Stanley       | 17498|   199|  1927|  1945|
  1564.      |    11|Ross, Stuart        | 13273|     0|  1931|  1932|
  1565.      |    13|Edwards, Peter      |  9899|   199|  1928|  1958|
  1566.      |    26|Thompson, Bob       | 14299|   199|  1930|  1970|
  1567.      |    32|Smythe, Carol       |  9954|   199|  1929|  1967|
  1568.      |    33|Hayes, Evelyn       | 11109|   199|  1931|  1963|
  1569.      |    37|Raveen, Lemont      | 13183|    26|  1950|  1974|
  1570.      |    55|James, Mary         | 13199|   199|  1920|  1969|
  1571.      |    98|Williams, Judy      |  9899|   199|  1935|  1969|
  1572.      |   129|Thomas, Tom         | 10999|   199|  1941|  1962|
  1573.      |   157|Jones, Tim          | 13199|   199|  1940|  1960|
  1574.      |   199|Bullock, J.D.       | 29699|     0|  1920|  1920|
  1575.      |   430|Brunet, Paul C.     | 19441|   129|  1938|  1959|
  1576.      |   843|Schmidt, Herman     | 12324|    26|  1936|  1956|
  1577.      |   994|Iwano, Masahiro     | 17205|   129|  1944|  1970|
  1578.      |  1330|Onstad, Richard     |  9656|    13|  1952|  1971|
  1579.      |  1523|Zugnoni, Arthur A.  | 21854|   129|  1928|  1949|
  1580.      |  1639|Choy, Wanda         | 12275|    55|  1947|  1970|
  1581.      |  4901|Bailey, Chas M.     |  9214|    32|  1956|  1975|
  1582.      |  5119|Ferro, Tony         | 14983|    55|  1939|  1963|
  1583.      |  5219|Williams, Bruce     | 14711|    33|  1944|  1959|
  1584.      |     0|Terrific, Tom       | 11000|     0|     0|     0|
  1585.      |-------------------------------------------------------|
  1586.  
  1587.      continue
  1588.      *
  1589.  
  1590.      Let's fire whoever has the smallest salary:
  1591.  
  1592.      * delete o where o.salary = min(o.salary) \g
  1593.      Executing . . .
  1594.  
  1595.  
  1596.      continue
  1597.      *
  1598.  
  1599.      Notice that the delete command requires  a  tuple  variable  (eg.
  1600.      delete o) and not a relation name.
  1601.  
  1602.      What if we wanted to know who makes more that Tom Terrific?   The
  1603.      query  to do this is very subtle.  First we use a new tuple vari-
  1604.      able called "t" which ranges over overpaid, and will be  used  to
  1605.      refer to Tom.  t.name must equal "Terrific, Tom".  Next, we use a
  1606.      tuple variable called "o" which will scan the whole relation.  If
  1607.      we  ever  find  an o.salary > t.salary then o.name must make more
  1608.      than Tom.
  1609.  
  1610.      The complete query is:
  1611.  
  1612.      * range of t is overpaid
  1613.      * retrieve (o.name, osal=o.salary, tomsal = t.salary)
  1614.      * where o.salary > t.salary
  1615.      * and t.name = "Terrific, Tom"
  1616.      * \g
  1617.      * Executing . . .
  1618.  
  1619.  
  1620.      |name                |osal  |tomsal|
  1621.      |----------------------------------|
  1622.      |Ross, Stanley       | 19247| 11000|
  1623.      |Ross, Stuart        | 14600| 11000|
  1624.      |Thompson, Bob       | 15728| 11000|
  1625.      |Hayes, Evelyn       | 12219| 11000|
  1626.      |Raveen, Lemont      | 14501| 11000|
  1627.      |James, Mary         | 14518| 11000|
  1628.      |Thomas, Tom         | 12098| 11000|
  1629.      |Jones, Tim          | 14518| 11000|
  1630.      |Bullock, J.D.       | 32668| 11000|
  1631.      |Brunet, Paul C.     | 21385| 11000|
  1632.      |Schmidt, Herman     | 13556| 11000|
  1633.      |Iwano, Masahiro     | 18925| 11000|
  1634.      |Zugnoni, Arthur A.  | 24039| 11000|
  1635.      |Choy, Wanda         | 13502| 11000|
  1636.      |Ferro, Tony         | 16481| 11000|
  1637.      |Williams, Bruce     | 16182| 11000|
  1638.      |----------------------------------|
  1639.  
  1640.      continue
  1641.      *
  1642.  
  1643.      If we wanted to give Tom Terrific $50 more than anyone else,  the
  1644.      query would be:
  1645.  
  1646.      * replace o(salary = max(o.salary) + 50)
  1647.      * where o.name = "Terrific, Tom"
  1648.      * \g
  1649.      Executing . . .
  1650.  
  1651.  
  1652.      continue
  1653.      *
  1654.  
  1655.      Finally, to destroy a relation owned by yourself, type  the  com-
  1656.      mand:
  1657.  
  1658.      * destroy overpaid
  1659.      * \g
  1660.      Executing . . .
  1661.  
  1662.  
  1663.      Continue
  1664.      *
  1665.  
  1666.      We are now ready to leave INGRES.  This is done either by  typing
  1667.      an  end-of-file  (control/d)  or more typically use the "\q" com-
  1668.      mand:
  1669.  
  1670.      * \q
  1671.      INGRES vers 6.1/0 logout
  1672.      Tue Aug 30 14:55:20 1977
  1673.      goodbye bob -- come again
  1674.  
  1675.